<?php

class Cat_Processor_Monkey extends Cat_Processor_Base
{
	const TAGTYPE_BLOCK = 'block';
	const TAGTYPE_LINE = 'line';

	/**
	 * Flag which indicates wheter @! sequence will be unescaped.
	 * 
	 * Defaults to true, but when processing tag bodies it can be bad idea.
	 * 
	 * @var bool
	 */
	private $monkey_screams = true;
	
	function makeMonkeyScreaming( $ms )
	{
		$this->monkey_screams = $ms;
	}
	
	function isMonkeyScreaming()
	{
		return $this->monkey_screams;
	}
	
	private $tag_handlers = array();
	
	function addTagHandler( Cat_Processor_Monkey_TagHandlerInterface $tag_handler )
	{
		$tag_handler->setProcessor( $this );
		$this->tag_handlers[] = $tag_handler;
	}
	
	function getTagHandlers()
	{
		return $this->tag_handlers;
	}
	
	function getTagObject( $name )
	{	
		foreach( $this->getTagHandlers() as $th )
		{
			$o = $th->getTagObject( $name );
			
			if ( $o != null )
			{
				return $o;				
			}
		}
		
		throw new Cat_Exception( Cat_Exception_Messages::NO_TAG_CLASS . " [$name]" );
	}
	
	private $patterns = array(
		'/(#|\/\*)?@@:[ \t]*?([a-zA-Z0-9\.]+?)(\s|\r?\n)(.*?)(:@@\*\/|:@@)/ms',
		'/(#|\/\*)?@@[ \t]*?([a-zA-Z0-9\.]+?)(\s*?)(@@\*\/|@@|\r?\n)/m',
		'/(#|\/\*)?@@[ \t]*?([a-zA-Z0-9\.]+?)\s(.*?)(@@\*\/|@@|\r?\n)/m',
	);
	
	private function replaceTags( $matches )
	{				
		$addlf = false;
		
		$o = $this->getTagObject( $matches[2] );	
		
		if ( isset( $matches[5] ) || ( strpos( $matches[4], "\n" ) !== false ) )
		{
			$addlf = true;
		}
		
		if ( isset( $matches[5] ) )
		{
			$o->setParam( 'args', $matches[4] );
			$o->setParam( 'tagtype', self :: TAGTYPE_BLOCK );
		}
		else
		{
			$o->setParam( 'args', $matches[3] );
			$o->setParam( 'tagtype', self :: TAGTYPE_LINE );			
		}
		
		$ret = $o->getOutput();
			
		if ( $addlf )
		{
			$ret .= "\n";
		}
		
		return $ret;
	}
	
	function processString( $string )
	{		
		foreach( $this->patterns as $pattern )
		{		
			$cnt = 1;
		
			while( $cnt )
			{
				$string = preg_replace_callback( $pattern, array( $this, 'replaceTags' ), $string, 1, $cnt );		
			}
		}	
		
		if ( $this->isMonkeyScreaming() )
		{
			$string = str_replace( '@!', '@', $string );
		}
		
		return $string;
	}
}

?>